#define _CRT_SECURE_NO_WARNINGS
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
#include <iostream>

// CRC-8 计算函数
uint8_t calculateCRC8(const std::vector<uint8_t>& data) {
    uint8_t crc = 0;
    for (uint8_t byte : data) {
        crc ^= byte;
        for (int i = 0; i < 8; ++i) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ 0x31;
            }
            else {
                crc <<= 1;
            }
        }
    }
    return crc;
}

// 生成黑白二维码并合成为视频
void generateBlackWhiteQRCode(const char* imgPath, const char* savePath, int maxFrames, int fps) {
    // 读取输入图像
    cv::Mat srcImg = cv::imread(imgPath);
    if (srcImg.empty()) {
        std::cerr << "Cannot read image: " << imgPath << std::endl;
        return;
    }

    // 不缩放输入图像，直接使用原始大小
    cv::Mat resizedImg = srcImg;

    // 编码为PNG，无压缩
    std::vector<uint8_t> buffer;
    std::vector<int> params;
    params.push_back(cv::IMWRITE_PNG_COMPRESSION);
    params.push_back(0);  // 无压缩，确保细节保留
    cv::imencode(".png", resizedImg, buffer, params);

    // 添加CRC校验
    uint8_t crc = calculateCRC8(buffer);
    buffer.push_back(crc);

    // 创建二维码编码器，使用默认参数（自动选择版本）
    cv::Ptr<cv::QRCodeEncoder> encoder = cv::QRCodeEncoder::create();

    // 计算所需帧数，减少每帧字节数
    int bytesPerFrame = 100;  // 从200减少到100字节
    size_t totalFrames = (buffer.size() + bytesPerFrame - 1) / bytesPerFrame;
    std::cout << "Total frames needed: " << totalFrames << std::endl;

    if (totalFrames > static_cast<size_t>(maxFrames)) {
        std::cerr << "Data too large, exceeds max frames." << std::endl;
        return;
    }

    // 创建临时目录
    system("if not exist temp mkdir temp");

    // 生成每一帧二维码
    for (size_t i = 0; i < totalFrames; ++i) {
        size_t start = i * bytesPerFrame;
        size_t end = std::min(start + bytesPerFrame, buffer.size());
        std::vector<uint8_t> frameData(buffer.begin() + start, buffer.begin() + end);

        try {
            // 生成黑白二维码
            cv::Mat qrCode;
            std::string dataStr(frameData.begin(), frameData.end());
            encoder->encode(dataStr, qrCode);

            // 放大二维码图像，scaleFactor=15
            int scaleFactor = 15;  // 放大15倍
            cv::Mat enlargedQR;
            cv::resize(qrCode, enlargedQR, cv::Size(), scaleFactor, scaleFactor, cv::INTER_NEAREST);

            // 保存二维码图像
            char framePath[256];
            sprintf(framePath, "temp/frame_%d.png", static_cast<int>(i));
            cv::imwrite(framePath, enlargedQR, params);

            std::cout << "Generated frame " << i + 1 << "/" << totalFrames << std::endl;
        }
        catch (const cv::Exception& e) {
            std::cerr << "Error generating QR code for frame " << i + 1 << ": " << e.what() << std::endl;
            std::cerr << "Data size: " << frameData.size() << " bytes" << std::endl;

            // 尝试减少数据量并重试
            if (frameData.size() > 50) {
                frameData.resize(frameData.size() / 2);
                std::cout << "Retrying with reduced data size: " << frameData.size() << " bytes" << std::endl;

                try {
                    cv::Mat qrCode;
                    std::string dataStr(frameData.begin(), frameData.end());
                    encoder->encode(dataStr, qrCode);

                    int scaleFactor = 15;
                    cv::Mat enlargedQR;
                    cv::resize(qrCode, enlargedQR, cv::Size(), scaleFactor, scaleFactor, cv::INTER_NEAREST);

                    char framePath[256];
                    sprintf(framePath, "temp/frame_%d.png", static_cast<int>(i));
                    cv::imwrite(framePath, enlargedQR, params);

                    std::cout << "Successfully generated frame with reduced data" << std::endl;
                }
                catch (const cv::Exception& e2) {
                    std::cerr << "Failed to generate frame even with reduced data: " << e2.what() << std::endl;
                    // 创建一个空白帧，避免中断视频生成
                    cv::Mat blankFrame(300, 300, CV_8UC1, cv::Scalar(255));
                    char framePath[256];
                    sprintf(framePath, "temp/frame_%d.png", static_cast<int>(i));
                    cv::imwrite(framePath, blankFrame);
                }
            }
            else {
                // 数据量已经很小，创建一个空白帧
                cv::Mat blankFrame(300, 300, CV_8UC1, cv::Scalar(255));
                char framePath[256];
                sprintf(framePath, "temp/frame_%d.png", static_cast<int>(i));
                cv::imwrite(framePath, blankFrame);
            }
        }
    }

    // 使用FFmpeg合成视频，优化编码质量
    char cmd[512];
    sprintf(cmd, "ffmpeg -y -framerate %d -i temp/frame_%%d.png -vf \"pad=width=1920:height=1080:x=(1920-iw)/2:y=(1080-ih)/2:color=white\" -c:v libx264 -tune stillimage -b:v 10M -pix_fmt yuv420p %s",
        fps, savePath);
    std::cout << "Running command: " << cmd << std::endl;
    system(cmd);

    // 清理临时文件
    system("rd /s /q temp");

    std::cout << "Video generation complete!" << std::endl;
}

int main(int argc, char* argv[]) {
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0] << " <input image> <output video> <max frames> <fps>" << std::endl;
        std::cerr << "Example: " << argv[0] << " input.png output.mp4 1000 10" << std::endl;
        return 1;
    }

    int maxFrames = atoi(argv[3]);
    int fps = atoi(argv[4]);

    generateBlackWhiteQRCode(argv[1], argv[2], maxFrames, fps);

    return 0;
}